package com.cats.bi.sqltool.basic;

import lombok.Data;

import java.util.Collection;
import java.util.Map;

/**
 * @author wang jian
 * @Description:
 * @create 2021/4/20
 */
@Data
public class Column extends AbstractTableColumn<Column> {
    public static final String ALL = "*";
    public final Object table;
    public final String name;
    private String tableAlias;

    public Column(String name) {
        this.table = null;
        this.name = name;
    }

    public Column(String table, String name) {
        this.table = table;
        this.name = name;
    }

    public Column(AbstractSearchable<?> table) {
        this.table = table;
        this.name = null;
    }

    public Column(AbstractSearchable<?> table, String name) {
        this.table = table;
        this.name = name;
    }

    public Column(AbstractSearchable<?> table, String tableAlias, String name) {
        this.table = table;
        this.tableAlias = tableAlias;
        this.name = name;
    }

    public Column as(String tableAlias, String nameAlias) {
        this.tableAlias = tableAlias;
        this.nameAlias = nameAlias;
        return this;
    }

    public Column tableAs(String tableAlias) {
        this.tableAlias = tableAlias;
        return this;
    }

    public Column nameAs(String nameAlias) {
        this.nameAlias = nameAlias;
        return this;
    }


    /**
     * table as tableAlias
     */
    @Override
    public void tableInFrom(StringBuilder sb) {
        if (table == null) {
            return;
        } else if (table instanceof AbstractSearchable) {
            sb.append('(');
            ((AbstractSearchable) table).toSql(sb);
            sb.append(')');
        } else {
            sb.append(table);
        }
        if (tableAlias != null) {
            sb.append(" AS ").append(tableAlias).append(' ');
        }
    }

    @Override
    public void signTable(Map<Object, AbstractTableColumn<?>> tables) {
        if (tableAlias != null) {
            tables.put(tableAlias, this);
        } else if (table != null) {
            tables.put(table, this);
        }
    }

    @Override
    public void unSignTable(Map<Object, AbstractTableColumn<?>> tables) {
        if (tableAlias != null) {
            tables.remove(tableAlias);
        } else if (table != null) {
            tables.remove(table);
        }
    }

    @Override
    public void toSql(StringBuilder sb) {
        if (name == null) {
            throw new NullPointerException("column name is null");
        }
        if (tableAlias != null) {
            sb.append(tableAlias).append('.');
        } else if (table instanceof String) {
            sb.append(table).append('.');
        }
        if (ALL.equals(name)) {
            sb.append(ALL);
        } else {
            sb.append(name);
        }

    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Column) {
            Column t = (Column) obj;
            return compare(name, t.name)
                    && compare(table, t.table)
                    && compare(nameAlias, t.nameAlias)
                    && compare(tableAlias, t.tableAlias);
        }
        return super.equals(obj);
    }


    private boolean compare(Object a, Object b) {
        if (a == null) {
            return b == null;
        }
        return a.equals(b);
    }

    public AbstractClause isNotNull() {
        return AbstractClause.isNotNull(this);
    }

    public AbstractClause isNull() {
        return AbstractClause.isNull(this);
    }

    public AbstractClause equalsWith(Object obj) {
        return AbstractClause.eq(this, obj);
    }

    public AbstractClause greaterEqual(Object pattern) {
        return AbstractClause.greaterEqual(this, pattern);
    }

    public AbstractClause greaterThan(Object pattern) {
        return AbstractClause.greaterThan(this, pattern);
    }

    public AbstractClause lessEqual(Object pattern) {
        return AbstractClause.lessEqual(this, pattern);
    }

    public AbstractClause lessThan(Object pattern) {
        return AbstractClause.lessThan(this, pattern);
    }

    public AbstractClause in(Collection<?> pattern) {
        return AbstractClause.in(this, pattern);
    }

    public AbstractClause in(Object... pattern) {
        return AbstractClause.in(this, pattern);
    }

    public AbstractClause in(int... array) {
        return AbstractClause.in(this, array);
    }

    public AbstractClause in(Select pattern) {
        return AbstractClause.in(this, pattern);
    }

    public AbstractClause like(String pattern) {
        return AbstractClause.like(this, pattern);
    }

    public AbstractClause contains(String pattern) {
        return AbstractClause.contains(this, pattern);
    }

    public AbstractClause startWith(String pattern) {
        return AbstractClause.startWith(this, pattern);
    }

    public AbstractClause endWith(String pattern) {
        return AbstractClause.endWith(this, pattern);
    }
}